from django.db import transaction
from django.db.models import Sum
from rest_framework import serializers
from rest_framework.exceptions import ValidationError

from BYD_ERP.utils.get_inventory import get_inventory_by_goods
from financial_info.models import ReceiptItemModel
from warehouse_info.models import OutStorageModel, OutStorageItemModel


class OutStorageItemSerializer(serializers.ModelSerializer):
    """
        出库单货品（项目）的序列化器
    """

    # 注意：只有库存数据在OutStorageItemModel中没有，可以增加一个属性
    # read_only=True：只是在序列化的时候用，不是在反序列化的时候用
    # 因为加了read_only=True，不会影响新增和修改
    cur_inventory = serializers.SerializerMethodField(read_only=True, label='在当前仓库中的库存')

    class Meta:
        model = OutStorageItemModel
        fields = '__all__'

    def get_cur_inventory(self, obj):
        result = get_inventory_by_goods(obj.goods.id, obj.warehouse.id)
        # 如果result有就返回result，如果result没有就返回0。
        return result if result else 0


class OutStorageSerializer(serializers.ModelSerializer):
    """
        新增和修改出库单的序列化和反序列化，查询列表的序列化器
    """
    # write_only=True
    item_list = OutStorageItemSerializer(many=True)
    # 出库单列表中需要展示：商品信息，多个商品的名称+规格，中间使用逗号隔开
    goods_info = serializers.SerializerMethodField(read_only=True, label='包含出库单中商品信息')
    # 查询当前销售出库单中已经到账的金额
    # read_only=True：只是在序列化的时候用，不是在反序列化的时候用
    # 因为加了read_only=True，不会影响新增和修改
    already_receipt = serializers.SerializerMethodField(read_only=True, help_text='已经到账的金额')

    class Meta:
        model = OutStorageModel
        fields = '__all__'

    def get_goods_info(self, obj):
        """
            商品信息：商品1名称+商品1规格，商品2名称+商品2规格，…………
        """
        # 使用.all()返回的是列表
        if obj.item_list.all():
            result = []
            for item in obj.item_list.all():
                result.append(item.name + (item.specification if item.specification else ''))
            return ','.join(result)
        return ''

    def get_already_receipt(self, obj: OutStorageModel):
        """
            查询当前销售出库单中已经收款的金额
            :param obj: OutStorageModel
            :return: 0或者其他数值
        """

        rece_dict = ReceiptItemModel.objects.filter(out_storage_id=obj.id).exclude(
            receipt__status='0').aggregate(sum=Sum('this_money'))
        if rece_dict:
            # 如果收过款就是rece_dict['sum']，否则就是0
            return rece_dict['sum'] if rece_dict['sum'] else 0
        return 0


    # 同时插入出库单和出库单中的货品项，必须重写create
    def create(self, validated_data):
        item_list = validated_data.pop('item_list')
        with transaction.atomic():
            out_storage = OutStorageModel.objects.create(**validated_data)
            for item in item_list:
                # out_storage销售出库单
                osi = OutStorageItemModel.objects.create(out_storage=out_storage, **item)
                # 同时把一些冗余的属性一块加进去
                goods = item.get('goods')
                osi.name = goods.name
                osi.specification = goods.specification
                osi.model_number = goods.model_number
                osi.category_name = goods.category.name
                osi.units = goods.units
                osi.units_name = goods.units.basic_name
                osi.save()
        return out_storage

    def update(self, instance, validated_data):
        # instance：就是正在修改的出库单
        if instance.status != '0':
            # 出库单的状态，0：未审核，1：已审核，2：部分收款，3：收款完成（包含欠款）
            raise ValidationError('出库单已经生效，不能修改')
        # 请求参数中的新项目数据
        item_list = validated_data.pop('item_list')
        # 如果之前有老数据（之前新增的出库单项目数据）是需要删除掉的
        old_list = instance.item_list.all()
        with transaction.atomic():
            if old_list.exists():
                # 把老数据删除
                old_list.delete()
            for item in item_list:
                # out_storage出库单
                osi = OutStorageItemModel.objects.create(out_storage=instance, **item)
                goods = item.get('goods')
                osi.name = goods.name
                osi.specification = goods.specification
                osi.model_number = goods.model_number
                osi.partner = goods.partner
                osi.units = goods.units
                osi.units_name = goods.units.basic_name
                osi.save()
            result = super(OutStorageSerializer, self).update(instance=instance, validated_data=validated_data)
        return result


class OutStorageGetSerializer(serializers.ModelSerializer):
    """
        仅仅用于查询展示出库单详情的序列化器
    """
    # 注意：只有库存数据，在OutStorageItemModel中没有，这就是冗余字段的好处
    item_list = OutStorageItemSerializer(many=True, read_only=True)

    class Meta:
        model = OutStorageModel
        fields = '__all__'
